﻿using System;
using System.IO;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Text.RegularExpressions;

namespace Utils.WP7.Bing.Controls
{
    [TemplatePart(Name = "ItemTextBlock", Type = typeof(TextBlock))]
    public class ItineraryItemBlock : Control
    {
        /// <summary>
        /// The textblock that will contain the text.
        /// </summary>
        private TextBlock textBlock;

        /// <summary>
        /// The text.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        /// <summary>
        /// Dependency property for text.
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", 
            typeof(string), typeof(ItineraryItemBlock), new PropertyMetadata("", OnTextChanged));

        /// <summary>
        /// When the text changes, update the content of the control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void OnTextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var item = sender as ItineraryItemBlock;
            if (item != null)
            {
                item.SetItinerary(e.NewValue as string);
            }
        }

        /// <summary>
        /// When the template is applied, find the textblock.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // Get textblock.
            textBlock = GetTemplateChild("ItemTextBlock") as TextBlock;
            if (textBlock == null)
                throw new InvalidOperationException("Unable to find 'ItemTextBlock' TextBlock in the template.");

            // Set the text if it was assigned before loading the template.
            if (!String.IsNullOrEmpty(Text))
                SetItinerary(Text);
        }

        /// <summary>
        /// Cleans the unnecessary elements from the itinerary.
        /// Reason is that TurnDir doesn't always close correctly and this causes a bug in the XmlReader.
        /// </summary>
        /// <param name="itinerary">The itinerary.</param>
        /// <returns></returns>
        private string CleanElements(string itinerary)
        {
            if (itinerary != null)
            {
                itinerary = itinerary.Replace("<VirtualEarth:Action>", String.Empty);
                itinerary = itinerary.Replace("</VirtualEarth:Action>", String.Empty);
                itinerary = itinerary.Replace("<VirtualEarth:TurnDir>", String.Empty);
                itinerary = itinerary.Replace("</VirtualEarth:TurnDir>", String.Empty);
            }

            // Done.
            return itinerary;
        }

        /// <summary>
        /// Sets the itinerary.
        /// </summary>
        /// <param name="text">The text.</param>
        protected void SetItinerary(string text)
        {
            if (textBlock != null)
            {
                textBlock.Inlines.Clear();

                // Clean up the itinerary.
                string itinerary = CleanElements(text);

                try
                {
                    // Read the input
                    string dummyXml = String.Format("<Itinerary xmlns:VirtualEarth=\"http://dummy\">{0}</Itinerary>", itinerary);
                    using (var stringReader = new StringReader(dummyXml))
                    {
                        // Trace the previous element.
                        string previousElement = "";

                        // Parse the dummy xml.
                        using (var xmlReader = XmlReader.Create(stringReader))
                        {
                            // Read each element.
                            while (xmlReader.Read())
                            {
                                // Add to textblock.
                                if (!String.IsNullOrEmpty(xmlReader.Value))
                                {
                                    if (previousElement.StartsWith("VirtualEarth:"))
                                    {
                                        textBlock.Inlines.Add(new Run() { Text = xmlReader.Value, FontWeight = FontWeights.Bold });
                                    }
                                    else
                                    {
                                        textBlock.Inlines.Add(new Run() { Text = xmlReader.Value });
                                    }
                                }

                                // Store the previous element.
                                if (xmlReader.NodeType == XmlNodeType.Element)
                                    previousElement = xmlReader.Name;
                                else
                                    previousElement = "";
                            }
                        }
                    }
                }
                catch
                {
                    // Strip all xml.
                    var regex = new Regex("<[/a-zA-Z:]*>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
                    textBlock.Inlines.Add(new Run() { Text = regex.Replace(itinerary, String.Empty) });
                }
            }
        }
    }
}
